1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.console.console; 12 import hip.config.opts; 13 import hip.util.reflection : isLiteral; 14 import hip.util.conv:to; 15 import hip.util.string : toStringz, String; 16 import hip.util.format; 17 18 19 enum Platforms 20 { 21 DEFAULT, 22 DESKTOP, 23 ANDROID, 24 UWP, 25 WASM, 26 PSVITA, 27 APPLEOS, 28 NULL 29 } 30 static enum androidTag = "HipremeEngine"; 31 enum GUI_CONSOLE = true; 32 33 ///If it is inside thread local storage, then, it won't work being called from another thread 34 __gshared void function(string toPrint) _log; 35 __gshared void function(string toPrint) _info; 36 __gshared void function(string toPrint) _warn; 37 __gshared void function(string toPrint) _err; 38 __gshared void function(string toPrint) _fatal; 39 version(PSVita) extern(C) void hipVitaPrint(uint length, const(char)* str); 40 41 version(UWP){} 42 else version(Windows) 43 version = WindowsNative; 44 45 version(WindowsNative) 46 { 47 import core.sys.windows.winbase; 48 import core.sys.windows.wincon; 49 } 50 51 52 enum WindowsConsoleColors 53 { 54 lightBlue = 1, 55 darkGreen = 2, 56 darkTeal = 3, 57 lightRed = 4, 58 pink = 5, 59 yellow = 6, 60 lightGrey = 7, 61 grey = 8, 62 blue = 9, 63 green = 10, 64 lightTeal = 11, 65 red = 12, 66 white = 15 67 } 68 69 class Console 70 { 71 string name; 72 String[] lines; 73 74 __gshared ushort idCount = 0; 75 ushort id; 76 77 private uint logCounter = 0; 78 __gshared Console DEFAULT; 79 80 string indentation; 81 int indentationCount; 82 int maxLines = 255; 83 int indentationSize = 4; //? Don't know if it should be used instead of \t 84 bool useTab = true; 85 bool isShowing = true; 86 87 88 static void install(Platforms p = Platforms.DEFAULT, void function(string) printFunc = null) 89 { 90 DEFAULT = new Console("Output", 99); 91 version(WindowsNative) 92 { 93 static void* windowsConsole; 94 if(windowsConsole is null) 95 windowsConsole = GetStdHandle(STD_OUTPUT_HANDLE); 96 } 97 switch(p) with(Platforms) 98 { 99 case NULL: 100 _log = function(string s){}; 101 _info = _log; 102 _warn = _log; 103 _err = _log; 104 _fatal = _err; 105 break; 106 case ANDROID: 107 version(Android) 108 { 109 import hip.jni.helper.androidlog; 110 _log = function(string s){alogi(androidTag, (s~"\0").ptr);}; 111 _info = _log; 112 _warn = function(string s){alogw(androidTag, (s~"\0").ptr);}; 113 _err = function(string s){aloge(androidTag, (s~"\0").ptr);}; 114 _fatal = function(string s){alogf(androidTag, (s~"\0").ptr);}; 115 } 116 break; 117 case PSVITA: 118 { 119 version(PSVita) 120 { 121 _log = function(string s){hipVitaPrint(s.length, s.ptr);}; 122 _info = _warn = _err = _fatal = _log; 123 } 124 break; 125 } 126 case WASM: 127 version(WebAssembly) 128 { 129 import arsd.webassembly; 130 _log = function(string s){eval(q{console.log.apply(null, arguments)}, s);}; 131 _fatal = _err = function(string s){eval(q{console.error.apply(null, arguments)}, s);}; 132 _warn = function(string s){eval(q{console.warn.apply(null, arguments)}, s);}; 133 _info = function(string s){eval(q{console.info.apply(null, arguments)}, s);}; 134 } 135 break; 136 case UWP: 137 _log = printFunc; 138 _info = _log; 139 _warn = _log; 140 _err = _log; 141 _fatal = _err; 142 break; 143 case DEFAULT: 144 case APPLEOS: 145 case DESKTOP: 146 default: 147 { 148 _log = function(string s) 149 { 150 version(WebAssembly) assert(false, s); 151 else 152 { 153 import core.stdc.stdio; 154 printf("%.*s\n", cast(int)s.length, s.ptr); 155 version(PSVita){} 156 else version(CustomRuntimeTest){} 157 else fflush(stdout); 158 } 159 }; 160 _info = function(string s) 161 { 162 version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.blue);} 163 _log(s); 164 version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.white);} 165 }; 166 _warn = function(string s) 167 { 168 version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.yellow);} 169 _log(s); 170 version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.white);} 171 }; 172 _err = function(string s) 173 { 174 version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.red);} 175 _log(s); 176 version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.white);} 177 }; 178 _fatal = function(string s) 179 { 180 version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.pink);} 181 _log(s); 182 version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.white);} 183 }; 184 break; 185 } 186 } 187 } 188 private this(string consoleName, ushort id) 189 { 190 lines = new String[maxLines]; 191 name = consoleName; 192 this.id = id; 193 } 194 195 this(string consoleName) 196 { 197 lines = new String[maxLines]; 198 name = consoleName; 199 id = idCount; 200 idCount++; 201 } 202 203 private void _formatLog(ref string log) 204 { 205 log~= indentation; 206 lines[logCounter++] = log; 207 if(logCounter > maxLines) 208 { 209 lines = lines[1..$]; 210 logCounter--; 211 } 212 } 213 private String formatArguments(Args...)(Args a) 214 { 215 String toLog = String(a); 216 // _formatLog(toLog); 217 return toLog; 218 } 219 220 void hipLog(Args...)(Args a) 221 { 222 lines~= formatArguments(a); 223 _log(lines[$-1].toString); 224 } 225 226 227 void log(Args...)(Args a) 228 { 229 static if(!HE_NO_LOG && !HE_ERR_ONLY) 230 { 231 //mtx.lock(); 232 _log(formatArguments(a).toString); 233 //mtx.unlock(); 234 } 235 } 236 237 void logStr(string str) 238 { 239 _info(str); 240 } 241 void info(Args...)(Args a) 242 { 243 static if(!HE_NO_LOG && !HE_ERR_ONLY) 244 { 245 //mtx.lock(); 246 _info("INFO: " ~ formatArguments(a).toString); 247 //mtx.unlock(); 248 } 249 } 250 251 void warn(Args...)(Args a) 252 { 253 static if(!HE_NO_LOG && !HE_ERR_ONLY) 254 { 255 //mtx.lock(); 256 _warn("WARNING: " ~ formatArguments(a).toString); 257 //mtx.unlock(); 258 } 259 } 260 261 void error(Args...)(Args a) 262 { 263 static if(!HE_NO_LOG) 264 { 265 //mtx.lock(); 266 _err("ERROR: " ~ formatArguments(a).toString); 267 //mtx.unlock(); 268 } 269 } 270 271 void fatal(Args...)(Args a) 272 { 273 static if(!HE_NO_LOG) 274 { 275 //mtx.lock(); 276 _fatal("FATAL ERROR: " ~formatArguments(a).toString); 277 //mtx.unlock(); 278 } 279 } 280 281 void indent() 282 { 283 //mtx.lock(); 284 if(useTab) 285 indentation~= "\t"; 286 else 287 for(int i = 0; i < indentationSize; i++) 288 indentation~= " "; 289 indentationCount++; 290 //mtx.unlock(); 291 } 292 293 void unindent() 294 { 295 //mtx.lock(); 296 if(useTab) 297 indentation = indentation[1..$]; 298 else 299 indentation = indentation[indentationSize..$]; 300 indentationCount--; 301 //mtx.unlock(); 302 } 303 } 304 305 void varPrint(A...)() 306 { 307 foreach(i, arg; A) 308 { 309 static if(isLiteral!(A[i])) 310 { 311 writeln(A[i]); 312 } 313 else 314 { 315 static if(is(typeof(A[i]) == string)) 316 writeln(typeof(A[i]).stringof ~ " ", A[i].stringof, " = ", "\"", A[i], "\""); 317 else 318 writeln(typeof(A[i]).stringof ~ " ", A[i].stringof, " = ", A[i]); 319 } 320 } 321 }